//统计类，用于统计性能指标
#pragma once
#include <iostream>
#include <chrono>
#include <vector>

#define KB (1024)
#define MB (1024 * KB)
#define GB (1024 * MB)   

using namespace std;
using TimePoint = std::chrono::time_point<std::chrono::high_resolution_clock>;

class Profiler_Statis{
private:
    int thread_count;
    //记录时间
    TimePoint start_time;
    TimePoint end_time;
    //记录每个线程的时间
    vector<double> time_list;
    //记录每个线程的IO次数
    vector<int> io_count_list;
    //记录每个线程的IO总大小
    vector<long long> io_size_list;
public:
    Profiler_Statis(int thread_count_){
        thread_count = thread_count_;
        io_count_list.resize(thread_count, 0);
        io_size_list.resize(thread_count, 0);
        time_list.resize(thread_count, 0);
    }

    void start(){
        start_time = std::chrono::high_resolution_clock::now();
    }

    void end(){
        end_time = std::chrono::high_resolution_clock::now();
    }

    TimePoint get_time(){
        return std::chrono::high_resolution_clock::now();
    }

    void add_io_count(int thread_id, int io_count){
        io_count_list[thread_id] += io_count;
    }

    void add_io_size(int thread_id, long long io_size){
        io_size_list[thread_id] += io_size;
    }

    void add_time(int thread_id, double time){
        time_list[thread_id] += time;
    }

    double elapsed_time(TimePoint start, TimePoint end){
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
        return static_cast<double>(duration.count()) / 1000.0; // 转换为毫秒
    }

    void io_print(){
        double time = elapsed_time(start_time, end_time);
        cout << "Time:\t\t" << time << " ms" << endl;
        //将每个线程的IO次数和IO大小求和并打印
        int sum_io_count = 0;
        long long sum_io_size = 0;
        double sum_time = 0;
        for(int i = 0; i < thread_count; i++){ 
            sum_io_count += io_count_list[i];
            sum_io_size += io_size_list[i];
            sum_time += time_list[i];
        }
        cout << "IO count:\t" << sum_io_count << endl;
        cout << "Total size:\t" << sum_io_size/MB << " MB" << endl;
        //计算带宽
        double bandwidth = (static_cast<double>(sum_io_size)/MB) / (time/1000);
        //用非科学计数法打印，保留3位小数
        cout.precision(3);
        cout << "Bandwidth:\t" << std::fixed << bandwidth << " MB/s" << endl;
        //打印IOPS
        double iops = (static_cast<double>(sum_io_count)) / (time/1000);
        cout << "IOPS:\t\t" << std::fixed << iops << " IOPS" << endl;
        //每个线程统计时间
        double avg_time_thread = sum_time/thread_count; //平均每个线程的耗时
        bandwidth = (static_cast<double>(sum_io_size)/MB) / (avg_time_thread/1000);
        cout << "Bandwidth(perT):" << std::fixed << bandwidth << " MB/s" << endl;
        //打印IOPS
        iops = (static_cast<double>(sum_io_count)) / (avg_time_thread/1000);
        cout << "IOPS(perT):\t" << std::fixed << iops << " IOPS" << endl;
    }

    void cal_print(){
        double time = elapsed_time(start_time, end_time);
        cout << "Time:\t\t" << time << " ms" << endl;
        //将每个线程的计算的向量数量和总大小求和并打印
        int sum_io_count = 0;
        long long sum_io_size = 0;
        double sum_time = 0;
        for(int i = 0; i < thread_count; i++){ 
            sum_io_count += io_count_list[i];
            sum_io_size += io_size_list[i];
            sum_time += time_list[i];
        }
        cout << "Cal vector:\t" << sum_io_count << endl;
        cout << "Total size:\t" << sum_io_size/MB << " MB" << endl;
        //平均计算一个向量的耗时
        double avg_time = (time*1000) / sum_io_count;
        cout << "Avg Time:\t" << std::fixed << avg_time << " us" << endl;
        //计算一秒能计算多少个向量
        double iops = (static_cast<double>(sum_io_count)) / (time/1000);
        cout << "IOPS:\t\t" << std::fixed << iops << " IOPS" << endl;
        //计算平均每个线程计算一个向量的耗时
        double avg_time_thread = ((sum_time*1000)/thread_count)/(sum_io_count/thread_count);
        cout << "Avg Time(perT):\t" << std::fixed << avg_time_thread << " us" << endl;
        //计算平均每个线程计算一个向量的带宽
        double avg_bandwidth_thread = (1000000/avg_time_thread)*thread_count;
        cout << "IOPS(perT):\t" << std::fixed << avg_bandwidth_thread << " IOPS" << endl;
    }

    ~Profiler_Statis(){}
};